package com.ajing.logextractor.consumer;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import com.ajing.logextractor.config.CommonHandlerConfig;
import com.ajing.logextractor.config.ExtractConfig;
import com.ajing.logextractor.extractor.AbstractExtractor;
import com.ajing.logextractor.extractor.ExtractorFactory;
import com.ajing.logextractor.filter.AbstractFilter;
import com.ajing.logextractor.filter.FilterFactory;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.Charset;
import java.util.List;

@Slf4j
public class LogMessageHandler {

    private final Boolean testMode;
    private final String handlerName;
    private final String filePath;
    private final String filePrefix;
    private final String fileEncoding;
    private final Integer maxFileHistory;
    private final AbstractFilter filter;
    private final String outputFormat;
    private AbstractExtractor[] extractors;
    private Object[] outputArgs;

    private final Logger logger;

    public LogMessageHandler(CommonHandlerConfig config, LoggerContext context) {
        this(config, context, false);
    }

    public LogMessageHandler(CommonHandlerConfig config, LoggerContext context, Boolean testMode) {
        this.testMode = testMode;
        this.handlerName = config.getHandlerName();
        this.filePath = config.getFilePath();
        this.filePrefix = config.getFilePrefix();
        if (null == config.getFileEncoding()) {
            this.fileEncoding = "utf-8";
        } else {
            this.fileEncoding = config.getFileEncoding();
        }
        if (null == config.getMaxFileHistory()) {
            this.maxFileHistory = 240;
        } else {
            this.maxFileHistory = config.getMaxFileHistory();
        }
        this.filter = FilterFactory.getFilter(config.getFilter());

        // 输出格式
        if (null == config.getOutputFormat()) {
            // throw new RuntimeException(String.format("[%s] - outputFormat field must be configured!", this.handlerName));
            this.outputFormat = "%s%n";
        } else {
            this.outputFormat = config.getOutputFormat();
        }
        ExtractConfig[] extractConfigs = config.getOutputExtracts();
        if (null != extractConfigs) {
            this.extractors = new AbstractExtractor[extractConfigs.length];
            for (int i = 0; i < extractConfigs.length; i++) {
                this.extractors[i] = ExtractorFactory.getExtractor(extractConfigs[i]);
            }
        }
        if (null != this.extractors) {
            outputArgs = new Object[this.extractors.length];
        }
        log.info(String.format("[%s] LogMessageHandler init success", handlerName));

        logger = context.getLogger(handlerName);
        if (!this.testMode) {
            logger.addAppender(buildAppender(context, filePath + filePrefix, handlerName, fileEncoding));
        }
    }

    public void handle(List<String> recordList) {
        StringBuilder stringBuilder = new StringBuilder();
        for (String record : recordList) {
            if (null != filter && !filter.filter(record)) {
                continue;
            }
            if (null != this.extractors && this.extractors.length > 0) {
                boolean allNull = true;
                for (int i = 0; i < this.extractors.length; i++) {
                    outputArgs[i] = this.extractors[i].extractDeal(record);
                    if (null != outputArgs[i]) {
                        allNull = false;
                    }
                }
                if (allNull) {
                    continue;
                }
                stringBuilder.append(String.format(outputFormat, outputArgs));
            } else {
                stringBuilder.append(String.format(outputFormat, record));
            }
        }
        if (!testMode) {
            logger.info(stringBuilder.toString());
        } else {
            log.info(String.format("[%s] test result: %s", handlerName, stringBuilder));
        }
    }

    public RollingFileAppender<ILoggingEvent> buildAppender(LoggerContext loggerContext, String logPath, String handlerName, String charset) {
        RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
        //appender的name属性
        appender.setName(handlerName);
        appender.setContext(loggerContext);

        //设置文件名
        appender.setFile(logPath + "-current.log");

        //设置日志文件输出格式
        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setContext(loggerContext);
        encoder.setPattern("%msg");
        encoder.setCharset(Charset.forName(charset));
        encoder.start();

        //设置日志记录器的滚动策略，默认只按小时生成，后续有需求再改配置化
        TimeBasedRollingPolicy<String> policy = new TimeBasedRollingPolicy<>();
        policy.setFileNamePattern(logPath + "-%d{yyyyMMddHH}.log");
        policy.setParent(appender); //设置父节点是appender
        policy.setContext(loggerContext);
        policy.setMaxHistory(maxFileHistory); // 设置最大文件历史
        policy.start();

        //加入下面两个节点
        appender.setRollingPolicy(policy);
        appender.setEncoder(encoder);
        appender.start();
        return appender;
    }

}
